#if ENABLE_SDKUTIL_WX && !UNITY_EDITOR
#define ENABLE_SDKUTIL_WX2
#endif

#if ENABLE_SDKUTIL_WX2
using WeChatWASM;
#endif

using System.Collections;
using UnityEngine;
using wnity.zframework;

namespace cframework.SDKUtil
{
    public class SDKShareData
    {
        public string title;
        public string query;
        public string imageUrl;
        public string imageId;
    }

    public class SDKUtil_WX: ISDKUtil
    {
        public static SDKUtil_WX _instance;

        public static SDKUtil_WX instance
        {
            get
            {
#if ENABLE_SDKUTIL_WX2
                if (_instance == null) _instance = new();
#endif
                return _instance;
            }
        }

        private SDKUtil_WX() { }

        public bool isInited { get; private set; }

        public IEnumerator InitSDK()
        {
#if ENABLE_SDKUTIL_WX2
            var initResult = new ISDKUtil.InitResult();
            if (isInited)
            {
                initResult.success = true;
                yield return initResult;
            }

            var callbacked = false;
            WX.InitSDK(code =>
            {
                callbacked = true;
                initResult.code = code;
                initResult.success = code == 200;
            });

            yield return new WaitUntil(() => callbacked);

            isInited = initResult.success;

            yield return initResult;
#else
            yield return new ISDKUtil.InitResult();
#endif
        }


        public IEnumerator Login(double timeout = 0) //timeout��λms
        {
#if ENABLE_SDKUTIL_WX2

            var loginResult = new ISDKUtil.LoginResult();
            var completed = false;
            var loginOption = new LoginOption
            {
                success = (result) =>
                {
                    loginResult.success = true;
                    loginResult.code = result.code;
                    loginResult.errMsg = result.errMsg;
                    //successResult = result;
                },
                fail = (result) =>
                {
                    loginResult.errno = result.errno;
                    loginResult.errMsg = result.errMsg;
                    //failedResult = result;
                },
                complete = (result) =>
                {
                    completed = true;
                    //completeResult = result;
                },
            };

            if (timeout > 0)
            {
                loginOption.timeout = timeout;
            }

            WX.Login(loginOption);

            yield return new WaitUntil(() => completed);

            yield return loginResult;
#else
            yield return new ISDKUtil.LoginResult();
#endif
        }


#if ENABLE_SDKUTIL_WX2
        WXOpenDataContext openDataContext;
#endif
        void InitOpenDataContext()
        {
#if ENABLE_SDKUTIL_WX2
            if (openDataContext == null)
            {
                openDataContext = WX.GetOpenDataContext(new OpenDataContextOption
                {
                    sharedCanvasMode = CanvasType.ScreenCanvas
                });
            }
#endif
        }



        public bool ShowOpenData(Texture tex, RectInt rect)
        {

            // 
            // ע�����ﴫx,y,width,height��Ϊ�˵����������ȷ�����x,y �Ǿ�����Ļ���Ͻǵľ��룬���ȴ� (int)RankBody.rectTransform.rect.width����canvas��UI Scale ModeΪ Constant Pixel Size����������õġ�
            /**
             * �����Ԫ��ռ���������ڵĻ���pivot ����Ϊ��0��0����rotation����Ϊ180�������ϽǾ�������Ļ�ľ���
             * ע�����ﴫx,y,width,height��Ϊ�˵����������ȷ�������Ϊ���������򲢲���ʹ�� Unity ������Ⱦ���ǿ���ѡ�������������Ⱦ����
             * ���Կ�����������Ҫ��ȷ�������¼�����������Ҫ��ȷ���߿������������а����ڵ�������������Ļ�е���������ϵ
             * ���� iPhone Xs Max �������ߴ��� 414 * 896��������а񱻻�������Ļ�����������ߴ�Ϊ 200 * 200����ô����� x,y,width,heightӦ���� 107,348,200,200
             * x,y �Ǿ�����Ļ���Ͻǵľ��룬���ȴ� (int)RankBody.rectTransform.rect.width����canvas��UI Scale ModeΪ Constant Pixel Size����������õ�
             * �����Scale With Screen Size��������Ϊ�Կ�����Ϊ���ţ���Ҫ��Ҫ��һ�»��㣬����canavs����Ϊ960��rawImage����Ϊ200 ����Ҫ���� referenceResolution ��һЩ����
             * ����������ʲô��Ļ����ģʽ�������Ŀ�ľ���Ϊ����� RawImage ����Ļ�о��Ե�λ�úͳߴ�
             */



#if ENABLE_SDKUTIL_WX2
            InitOpenDataContext();
            WX.ShowOpenData(tex, rect.x, rect.y, rect.width, rect.height);
            return true;
#else
            return false;
#endif
        }

        public void HideOpenData()
        {
#if ENABLE_SDKUTIL_WX2
            WX.HideOpenData();
#endif
        }



        public void PostOpenDataMsg<T>(T t)
        {
#if ENABLE_SDKUTIL_WX2
            InitOpenDataContext();

            string msg = JsonUtility.ToJson(t);
            openDataContext.PostMessage(msg);
#endif
        }

        public void Share(SDKShareData data)
        {
#if ENABLE_SDKUTIL_WX2
            var option = new ShareAppMessageOption
            {
                title = data.title,
                imageUrlId = data.imageId,
                query = data.query,
                imageUrl = data.imageUrl
            };
            WX.ShareAppMessage(option);
#endif
        }

//#if ENABLE_SDKUTIL_WX2

//        WXRewardedVideoAd _ad;
//        bool adLoaded = false;
//        //bool adLoadCallbacked = false;
//#endif

//        public IEnumerator InitAd(string adUnitId)
//        {
//            var success = false;
//#if ENABLE_SDKUTIL_WX2
//            // ����ʼ��,���Զ���ȡ���һ��
//            _ad = WX.CreateRewardedVideoAd(new WXCreateRewardedVideoAdParam
//            {
//                adUnitId = adUnitId,
//            });


//            var adLoadCallbacked = false;
//            void onLoad(WXADLoadResponse response) //onload�������Զ���ȡ���Ļص�����������ʱ��ȡ��һ����棬����ʾ���ɹ����Զ���ȡ��һ�����
//            {
//                success = true;
//                adLoadCallbacked = true;
//                //adLoaded = response.errMsg != null;
//            }
//            _ad.OnLoad(onLoad);


//            void onError(WXADErrorResponse response)
//            {
//                adLoadCallbacked = true;

//                var _adErrorCode = response.errCode;

//                Debug.LogError($"ad error: {response.errCode} | {response.errMsg}");

//                switch (_adErrorCode)
//                {
//                    case 0:
//                        //if (!_adLoadComplete)
//                        //{
//                        //    StartLoadAD();//δ��������
//                        //                  //_adResult.data = "�����δ׼������";
//                        //                  //_adResult.errMsg = "�����δ׼������";
//                        //    _adResult.data = "���޹��,��ʹ�÷���";
//                        //    _adResult.errMsg = "��������:" + _adErrorCode;
//                        //}
//                        //else
//                        //{
//                        //    _adResult.data = "���޹��,��ʹ�÷���";
//                        //    _adResult.errMsg = "��������:" + _adErrorCode;
//                        //}
//                        //_adResult.code = -1;//����������Ϊ0
//                        break;
//                    case 1000://��˵��ô���
//                    case 1003://��˵��ô���
//                    case 1004://���ʺϵĹ��
//                    case 1005://�����������
//                    case 1006://������������
//                    case 1007://�����������
//                    case 1008://��浥Ԫ�ѹر�
//                        //_adResult.data = "���޹��,��ʹ�÷���";
//                        //_adResult.errMsg = "��������:" + _adErrorCode;
//                        break;
//                    case 1001://��������
//                    case 1002://id����
//                        //Debug.LogError($"����������{_adErrorCode}");
//                        //_adResult.data = "���޹��,��ʹ�÷���";
//                        //_adResult.errMsg = "��������:" + _adErrorCode;
//                        break;
//                    case 99999://�Զ���
//                        //_adResult.data = "��������ʧ��,�Ժ�����";
//                        //_adResult.errMsg = "��������ʧ��,�Ժ�����";
//                        break;
//                    default://���ڴ�������
//                        //_adResult.data = "��������ʧ��,�Ժ�����";
//                        //_adResult.errMsg = "��������:" + _adErrorCode;
//                        break;
//                }
//            }
//            _ad.OnError(onError);

//            yield return new WaitUntil(() => adLoadCallbacked);

//            _ad.OffLoad(onLoad);
//            _ad.OffError(onError);
//#endif
//            yield return success;
//        }

//        public IEnumerator ShowAd(string branchId = null, string branchDim = null)
//        {
//            var canReward = false;
//#if ENABLE_SDKUTIL_WX2
//            //yield return new WaitUntil(() => adLoadCallbacked); //�ȴ��Զ���ȡ

//            //if(!adLoaded) //�Զ���ȡʧ�ܣ�ֻ���ֶ���ȡ
//            //{
//            //    var retryCount = 1;
//            //    var j = 0;
//            //    for (; j < retryCount; j++)
//            //    {
//            //        var w = LoadAd().WithResult();
//            //        yield return w;
//            //        var loadSuccess = (bool)w.Current;
//            //        if (!loadSuccess)
//            //        {
//            //            yield return false;
//            //            yield break;
//            //        }
//            //    }
//            //}

//            var onCloseCallbacked = false;

//            void OnClose(WXRewardedVideoAdOnCloseResponse res)
//            {
//                if (res != null && res.isEnded)
//                {
//                    // �������Ž����������·���Ϸ����
//                    onCloseCallbacked = true;
//                    canReward = true;
//                }
//                else
//                {
//                    // ������;�˳������·���Ϸ����
//                    onCloseCallbacked = true;
//                }
//            };

//            int showRetryCount = 3;
//            _ad.OnClose(OnClose);
//            for (var i = 0; i < showRetryCount; i++)
//            {
//                yield return new WaitUntil(() => adLoaded);

//                var callbacked = false;
//                var showSuccess = false;
//                if (branchDim != null && branchId != null)
//                {
//                    _ad.Show(branchId, branchDim, (response) =>
//                    {
//                        showSuccess = true;
//                        callbacked = true;
//                    },
//                    (response) =>
//                    {
//                        callbacked = true;
//                    });
//                }
//                else
//                {
//                    _ad.Show((response) =>
//                    {
//                        showSuccess = true;
//                        callbacked = true;
//                    },
//                    (response) =>
//                    {
//                        callbacked = true;
//                    });
//                }

//                yield return new WaitUntil(() => callbacked);

//                if (!showSuccess) //��ʾʧ�ܣ�ֻ���ֶ���ȡ
//                {
//                    //var retryCount = 1;
//                    //var j = 0;
//                    //for (; j < retryCount; j++)
//                    //{ 
//                    //    var w = LoadAd().WithResult();
//                    //    yield return w;
//                    //    var loadSuccess = (bool)w.Current;
//                    //    if(loadSuccess)
//                    //    {
//                    //        break;
//                    //    }
//                    //}

//                    //if(j == retryCount)
//                    //{
//                    //    _ad.OffClose(OnClose);
//                    //    yield return false;
//                    //    yield break;
//                    //}

//                    adLoaded = false;
//                    continue;
//                }
//                //else //show�ɹ�����Զ���ȡ��һ�����
//                //{
//                //    adLoadCallbacked = false;
//                //    adLoaded = false;
//                //}

//                yield return new WaitUntil(() => onCloseCallbacked);
//                adLoaded = false;

//                _ad.OffClose(OnClose);
//                yield return canReward;
//                yield break;
//            }

//            _ad.OffClose(OnClose);
//#endif
//            yield return false;
//            yield break;

//        }

//        public IEnumerator LoadAd()
//        {
//            var success = false;
//#if ENABLE_SDKUTIL_WX2
//            var callbacked = false;

//            _ad.Load(success: (SuccessRes) =>
//                    {
//                        callbacked = true;
//                        success = true;
//                    },
//                    failed: (failRes) =>
//                    {
//                        callbacked = true;
//                    });

//            yield return new WaitUntil(() => callbacked);
//#endif
//            yield return success;
//        }


//        public IEnumerator LoadAdLoop()
//        {
//#if ENABLE_SDKUTIL_WX2
//            while (true)
//            {
//                yield return new WaitUntil(() => !adLoaded);
//                var w = LoadAd().WithResult();
//                yield return w;
//                var loadSuccess = (bool)w.Current;
//                adLoaded = loadSuccess;
//            }
//#else
//            yield return null;
//#endif
//        }

        public class AuthorizeResult
        {
            public string errMsg;
        }

        public IEnumerator Authorize(string scope) //"scope.userInfo", "scope.userFuzzyLocation"
        {
            AuthorizeResult result = new();
#if ENABLE_SDKUTIL_WX2
            AuthorizeOption option = new AuthorizeOption();
            option.scope = scope;


            bool calbacked = false;
            option.success = (res) =>
            {
                calbacked = true;
            };
            option.fail = (res) =>
            {
                result.errMsg = res.errMsg;
                calbacked = true;
            };

            WX.Authorize(option);

            yield return new WaitUntil(() => calbacked);

#endif
            yield return result;
        }


        public class GetUserInfoResult
        {
            public string avatarUrl;
            public string nickname;
            public string errMsg;
            public int errCode;

            //#if ENABLE_SDKUTIL_WX2

            //            //public GetUserInfoSuccessCallbackResult successResult;
            //            //public GeneralCallbackResult failedResult;
            //#endif
        }

        public string scope_userInfo = "scope.userInfo";


        public IEnumerator AuthorizeUserInfo()
        {
            var w = Authorize(scope_userInfo).WithResult();
            yield return w;
            var authorizeResult = (AuthorizeResult)w.Current;

            
            yield return authorizeResult;

        }

        public IEnumerator GetUserInfo()
        {
            var result = new GetUserInfoResult();



#if ENABLE_SDKUTIL_WX2
            var option = new GetUserInfoOption
            {
                withCredentials = true,
                lang = "zh_CN",
            };

            var callbacked = false;
            option.success = (res) =>
            {
                result.avatarUrl = res.userInfo.avatarUrl;
                result.nickname = res.userInfo.nickName;
            };
            option.fail = (res) =>
            {
                result.errMsg = res.errMsg;
            };
            option.complete = (res) =>
            {
                callbacked = true;
            };

            WX.GetUserInfo(option);

            yield return new WaitUntil(() => callbacked);
#endif
            yield return result;

        }


        public class GetFuzzyLocationResult
        {
#if ENABLE_SDKUTIL_WX2
            public GetFuzzyLocationSuccessCallbackResult successResult;
            public GeneralCallbackResult failedResult;
#endif
        }


        public IEnumerator GetFuzzyLocation(string type = "gcj02")
        {
            GetFuzzyLocationResult result = new();
#if ENABLE_SDKUTIL_WX2
            GetFuzzyLocationOption option = new();
            option.type = type;


            bool calbacked = false;
            option.success = (res) =>
            {
                result.successResult = res;
            };
            option.fail = (res) =>
            {
                result.failedResult = res;
            };

            option.complete = (res) =>
            {
                calbacked = true;
            };

            WX.GetFuzzyLocation(option);

            yield return new WaitUntil(() => calbacked);
#endif
            yield return result;
        }

        public class ShowModalResult
        {
#if ENABLE_SDKUTIL_WX2
            public ShowModalSuccessCallbackResult successResult;
            public GeneralCallbackResult failedResult;
#endif
        }

        public IEnumerator ShowModal(string title, string content)
        {
            var result = new ShowModalResult();
#if ENABLE_SDKUTIL_WX2
            var option = new ShowModalOption()
            {
                title = title,
                content = content,
                success = res =>
                {

                }
            };

            var callbacked = false;
            option.complete = (res) =>
            {
                
                callbacked = true;
            };

            option.success = (res) =>
            {
                result.successResult = res;
            };

            option.fail = (res) =>
            {
                result.failedResult = res;
            };

            WX.ShowModal(option);

            yield return new WaitUntil(() => callbacked);
#endif
            yield return result;


        }

#if ENABLE_SDKUTIL_WX2
        static GetSettingSuccessCallbackResult wxSetting;
#endif
        public IEnumerator GetSetting()
        {
            var complete = false;
#if ENABLE_SDKUTIL_WX2
            GeneralCallbackResult failedResult = new();
            GetSettingSuccessCallbackResult successRes = new();
            var option = new GetSettingOption()
            {
                success = (res)=>
                {
                    successRes = res;
                },
                fail = (res)=>
                {
                    failedResult = res;
                },
                complete = (res) =>
                {
                    complete = true;
                },
            };

            WX.GetSetting(option);

            yield return new WaitUntil(() => complete);

            if (!string.IsNullOrEmpty(failedResult.errMsg))
            {
                successRes.errMsg = failedResult.errMsg;
                //Debug.LogError(failedResult.errMsg);
                yield return successRes;
                yield break;
            }

            wxSetting = successRes;
            yield return successRes.errMsg != null;
#else
            yield return false;
#endif

            //Debug.Log("authSetting:");
            //foreach (var e in successRes.authSetting)
            //{
            //    Debug.Log(e.Key + " | " + e.Value);
            //}

            //Debug.Log("miniprogramAuthSetting:");
            //foreach (var e in successRes.miniprogramAuthSetting)
            //{
            //    Debug.Log(e.Key + " | " + e.Value);
            //}

            //Debug.Log("subscriptionsSetting:");
            //foreach (var e in successRes.subscriptionsSetting)
            //{
            //    Debug.Log(e.Key + " | " + e.Value);
            //}
        }


        public bool ContainsAuth(string auth)
        {
#if ENABLE_SDKUTIL_WX2
            return wxSetting != null && wxSetting.authSetting.ContainsKey(auth) && wxSetting.authSetting[auth];
#else
            return false;
#endif
        }

#if ENABLE_SDKUTIL_WX2
        WXUserInfoButton userInfoBtn;
#endif
        public IEnumerator CreateUserInfoButton(RectInt screenRect, bool withCredentials = false, string lang = "zh_CN")
        {
            var result = new GetUserInfoResult();

#if ENABLE_SDKUTIL_WX2
            if (userInfoBtn != null)
            {
                yield return false;
                yield break;
            }

            var callbacked = false;
            //WXUserInfoResponse resp = new();
            userInfoBtn = WX.CreateUserInfoButton(screenRect.x, screenRect.y, screenRect.width, screenRect.height, lang, withCredentials);
            userInfoBtn.OnTap(res =>
            {
                //resp = res;
                result.avatarUrl = res.userInfo.avatarUrl;
                result.nickname = res.userInfo.nickName;
                result.errMsg = res.errMsg;
                result.errCode = res.errCode;
                callbacked = true;
            });

            yield return new WaitUntil(() => callbacked);

            yield return result;
#else
            yield return result;
#endif
        }

        public void DestroyUserInfoButton()
        {
#if ENABLE_SDKUTIL_WX2
            if(userInfoBtn == null)
            {
                return;
            }

            userInfoBtn.Destroy();
            userInfoBtn = null;
#endif
        }


        public IEnumerator CanvasToTempFilePath(RectInt rect, Vector2Int destSize)
        {
#if ENABLE_SDKUTIL_WX2
            WeChatWASM.WXToTempFilePathParam param = new();
            param.x = rect.x;
            param.y = rect.y;
            param.width = rect.width;
            param.height = rect.height;
            param.destWidth = destSize.x;
            param.destHeight = destSize.y;

            var callbacked = false;
            WeChatWASM.ToTempFilePathParamSuccessCallbackResult result = new();
            param.success = (res) =>
            {
                result = res;
            };
            param.fail = (res) =>
            { };
            param.complete = (res) =>
            {
                callbacked = true;
            };

            WeChatWASM.WXCanvas.ToTempFilePath(param);
            yield return new WaitUntil(() => callbacked);

            yield return result.tempFilePath;
#else
            yield return "";
#endif
        }


        public IEnumerator WriteFile(string filePath, byte[] data)
        {
#if ENABLE_SDKUTIL_WX2
            var a = new WeChatWASM.WriteFileParam();
            a.data = data;
            a.filePath = $"{WeChatWASM.WX.env.USER_DATA_PATH}/{filePath}";
            var callbacked = false;
            var success = false;
            a.success = (res) =>
            {
                success = true;
            };
            a.fail = (res) =>
            {

            };
            a.complete = (res) =>
            {
                callbacked = true;
            };
            WeChatWASM.WX.GetFileSystemManager().WriteFile(a);

            yield return new WaitUntil(() => callbacked);

            yield return success ? a.filePath : "";
#else
            yield return "";
#endif
        }

        public IEnumerator AccessFile(string filePath)
        {
#if ENABLE_SDKUTIL_WX2
            var a = new WeChatWASM.AccessParam();
            a.path = $"{WeChatWASM.WX.env.USER_DATA_PATH}/{filePath}";
            var callbacked = false;
            var success = false;
            a.success = (res) =>
            {
                success = true;
            };
            a.fail = (res) =>
            {

            };
            a.complete = (res) =>
            {
                callbacked = true;
            };
            WeChatWASM.WX.GetFileSystemManager().Access(a);

            yield return new WaitUntil(() => callbacked);

            yield return success? a.path: "";
#else
            yield return "";
#endif
        }


        public void OnShareAppMessage(SDKShareData data, System.Func<SDKShareData> callback = null)
        {
#if ENABLE_SDKUTIL_WX2
            WeChatWASM.WXShareAppMessageParam shareParam = new();
            shareParam.title = data.title;
            shareParam.imageUrl = data.imageUrl;
            WeChatWASM.WX.OnShareAppMessage(shareParam, callback != null?(a) =>
            {
                var data2 = callback();

                if(data2 != null)
                {
                    WeChatWASM.WXShareAppMessageParam shareParam2 = new();
                    shareParam2.title = data2.title;
                    shareParam2.imageUrl = data2.imageUrl;
                    a(shareParam2);
                }
                else
                {
                    a(null);
                }

            }: null);
#endif
        }

        public string GetPlatform()
        {
#if ENABLE_SDKUTIL_WX2
            var systemInfo = WeChatWASM.WX.GetSystemInfoSync();
            return systemInfo.platform;
#else
            return null;
#endif

        }

        public bool isDevTool()
        {
#if ENABLE_SDKUTIL_WX2
            var systemInfo = WeChatWASM.WX.GetSystemInfoSync();
            return systemInfo.platform == "devtools";
#else
            return false;
#endif
        }

        public Rect GetSafeArea()
        {
#if ENABLE_SDKUTIL_WX2
            var info = WeChatWASM.WX.GetSystemInfoSync();
            var safeArea = info.safeArea;
            if (safeArea == null)
            {
                //Debug.LogError("safe area  is null");
                return Rect.zero;
            }


            var left = (safeArea.left / info.windowWidth) * Screen.width;
            var right = (safeArea.right / info.windowWidth) * Screen.width;
            var bottom = ((info.windowHeight - safeArea.bottom) / info.windowHeight) * Screen.height;
            var top = ((info.windowHeight - safeArea.top) / info.windowHeight) * Screen.height;

            var unitySafeArea = new Rect((float)left, (float)bottom, (float)right - (float)left, (float)(top - bottom));

            return unitySafeArea;
#else
            return Rect.zero;
#endif
        }


        //WX.GetLaunchOptionsSync();
        //WXUserInfoButton button = WX.CreateUserInfoButton(0, 0, Screen.width, Screen.height, "zh_CN", true);
        //WX.GetUpdateManager();
        //WX.GetSetting
        //WX.GetWindowInfo()
        //WX.VibrateShort(option);
        //WX.OnShow
        //WX.OnHide(WXOnHide);
        //WX.GetSystemInfo
        //WX.StartAccelerometer(s);
        //WX.OnAccelerometerChange(ShakePhone);
        //WX.OpenCustomerServiceConversation(new OpenCustomerServiceConversationOption
        //WX.CreateGameClubButton
        //WX.GetGameClubData
        //WX.NavigateToMiniProgram
        //WX.ExitMiniProgram
        //WX.RestartMiniProgram
        //WX.WriteLog
        //WX.WriteWarn
        //WX.OnShareMessageToFriend
        //WX.ShowKeyboard
        //WX.OnKeyboardInput(OnInput);
        //WX.OnKeyboardConfirm(OnConfirm);
        //WX.OnKeyboardComplete(OnComplete);

        //WX.HideKeyboard(new HideKeyboardOption()
        //{ success = successHide, fail = failHide, complete = comHide });
        //    //ɾ��������¼�����
        //    WX.OffKeyboardInput(OnInput);
        //    WX.OffKeyboardConfirm(OnConfirm);
        //    WX.OffKeyboardComplete(OnComplete);
        //WX.RequestSubscribeMessage
    }


}